defmodule EnumKit do
	@moduledoc false


	@doc """
	遍历 list, reduce(一次只能遍历一个) => (reduce_list)一次遍历多个
	[x1,x2,x3|rest]
	fun 返回:{rest, acc}, rest, 直到rest 为[] 结束遍历
	"""
	def reduce_list([], acc, _fun) do
		acc
	end
	def reduce_list(list, acc, fun) when is_list(list) and is_function(fun, 2) do
		case fun.(list, acc) do
			{[], acc} ->
				acc
			{rest, acc} ->
				reduce_list(rest, acc, fun)
		end
	end

	@doc """
	reduce 和 map_join 的结合
	example:
	    reduce_map_join(%{"a" => 1, "b" => 2, "c" => 3}, ", ", [],
	        fn ({key, val}, acc) ->
	            {"key: val", [{key, val} | acc]}
	        end),
	    返回: {"a: 1, b: 2, c: 3", [{"c", 3}, {"b", 2}, {"a", 1}]}
	"""
	@spec reduce_map_join(keyword | map | list, charlist, any, function) :: {charlist, any}
	def reduce_map_join(enum, joiner, acc1, fun) when is_function(fun, 2) do
		{entrys, acc} =
			Enumerable.reduce(
				enum,
				{:cont, {[], acc1}},
				fn x, {entry_acc, acc} ->
					case fun.(x, acc) do
						:skip ->
							{:cont, {entry_acc, acc}}
						{entry, acc} ->
							if entry_acc == [] do
								{:cont, {[entry], acc}}
							else
								{:cont, {[entry_acc, joiner | entry], acc}}
							end

					end
				end
			)
			|> elem(1)
		{IO.iodata_to_binary(entrys), acc}
	end


	@doc """
	fun: 返回 :break, 停止遍历;否则继续遍历
	"""
	@spec foreach(keyword | map | list, any, function) :: any
	def foreach(enum, acc1, fun) when is_function(fun, 2) do
		Enumerable.reduce(
			enum,
			{:cont, acc1},
			fn
				_x, {:break, acc} -> {:halt, acc}
				x, acc -> {:cont, fun.(x, acc)}
			end
		)
		|> elem(1)
	end

	def filter_map(enumerable, filter, mapper) when is_list(enumerable) do
		for element <- enumerable, filter.(element), do: mapper.(element)
	end


	def test_reduce_map_join() do
		reduce_map_join(
			#            %{"a" => 1, "b" => 2, "c" => 3},
			%{},
			", ",
			[],
			fn ({key, val}, acc) ->
				{"#{key}: #{val}", [{key, val} | acc]}
			end
		)
	end

	def test_filter_map() do
		filter_map([%{"a" => 1}, %{"b" => 2}], &(Map.get(&1, "a") in [1, 2] || Map.get(&1, "b") in [1, 2]), &Map.keys(&1))
	end

end
